package com.lzl.springboot.test;


import lombok.val;

import java.util.*;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Supplier;

public class LambdaApp {


    @FunctionalInterface
    interface Greet {
        void say(int a, int b);

        default void say1(String s) {
            System.out.println("日了狗了" + s);
        }
    }

    public void sayHello(int a, int b, Greet greet) {
        greet.say(a, b);
    }

    public void sayHello1(String s, Greet greet) {
        greet.say1(s);
    }

    public static void main(String[] args) {
        Map set=new HashMap();
        set.put("1","1");

//        CompletableFuture<Integer> cc=CompletableFuture.supplyAsync(()->{
//            return 0;
//        });
//        CompletableFuture<Integer> dd=CompletableFuture.supplyAsync(new Supplier<Integer>() {
//            @Override
//            public Integer get() {
//                return 0;
//            }
//        });
//        Arrays.asList("d","1","asdsddd","idea","eclipse").forEach(e->{
//            System.out.println(e);
//            byte[] b=e.getBytes();
//            for (byte bb:b) {
//                System.out.println(bb);
//            }
//        });
//        LambdaApp lambdaApp=new LambdaApp();
//        lambdaApp.sayHello(1,2,(a,b) ->{
//            System.out.println(a+b);
//            System.out.println("真是无聊啊");
//        });
//        lambdaApp.sayHello1("lam", new Greet() {
//            @Override
//            public void say(int a, int b) {
//                System.out.println(a+b);
//            }
//        });
//
        Function<Integer,Integer> fun=(a)-> a+1;
        Integer b=fun.apply(100);
        System.out.println(fun.apply(100));
    }

    /**
     * 方法引用 ，形式有三种： 1、实例::实例方法名     2、 类名::静态方法名     3、类名::实例方法名
     */
    public void test1() {
        Person person = new Person("小明", 18);

        Supplier<String> supplier = () -> person.getName();
        System.out.println(supplier.get());

        //上面lambda体只用到person实例的getName()方法，因此可以改写成实例::实例方法名
        Supplier<String> supplier1 = person::getName;
        System.out.println(supplier1.get());
    }

    public static void test2() {
        //普通lambda方式
        Comparator<Integer> com = (x, y) -> Integer.compare(x, y);

        //类名：静态方法名
        Comparator<Integer> com2 = Integer::compare;
    }

    public void test3() {
        String[] strArray = {"a", "c", "b"};
        Arrays.sort(strArray, (s1, s2) -> s1.compareTo(s2));
        //类名::实例方法名 前提：Lambda 参数列表的第一个参数，是实例方法的调用者，第二个参数(或无参)是实例方法的参数。
        //lambda的第一个参数s1 是实例方法compareTo()的调用者
        //且lambda的第二个参数s2 是compareTo()的参数
        Arrays.sort(strArray, String::compareTo);
    }

    /**
     *构造器引用 ，形式有一种： 类名::new
     */
    //4. 类名::new ，前提：构造器的参数列表，需要与函数式接口中参数列表保持一致
    public void test4(){
        // Function的参数为String，匹配 public Person(String name)
        Function<String, Person> fun = Person::new;

        //BiFunction的参数为String，Integer，匹配 public Person(String name, int age)
        BiFunction<String, Integer, Person> fun2 = Person::new;
    }
    /**
     * 数组引用  ，形式有一种：类型[]::new
     */
    public static void test5() {
        Function<Integer, String[]> fun = (length) -> new String[length];
        String[] strs1 = fun.apply(10);
        System.out.println(strs1.length);

        System.out.println("--------------------------");

        Function<Integer, String[]> fun2 = String[]::new;
        String[] strs2 = fun2.apply(20);
        System.out.println(strs2.length);
    }
    //当lambda体中的方法有泛型时，可以在双冒号:: 之后指定类型。
    public interface MyFunc<T> {
        int func(T[] als, T v);
    }

    public static class MyArrayOps {
        //统计v在数组中出现的次数
        public static <T> int countMatching(T[] array, T v) {
            int count = 0;
            for (T t : array) {
                if (t.equals(v)) count++;
            }
            return count;
        }
    }

    public static class Run {

        public static <T> int myOp(MyFunc<T> f, T[] array, T v) {
            return f.func(array, v);
        }

        public static void main(String[] args) {
            Integer[] vals = {1, 2, 3, 4, 2, 3, 4, 4, 5};
            String[] strs = {"One", "Two", "Three", "Two"};

            //不指定MyFunc类型时，可根据后面的参数推断
            int count1 = myOp(MyArrayOps::countMatching, vals, 4);
            System.out.println("vals contains " + count1 + " 4s");

            //要指定类型时，可以在::后面指定，指定完可以限制后面两个参数的类型
            int count2 = myOp(MyArrayOps::<String>countMatching, strs, "Two");
            System.out.println("strs contains " + count2 + " Twos");

        }
    }
}
